//////////////////////////////////////////////
// Component.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Forward declarations ---------------------

namespace nkExport
{
	class Node ;
}

namespace nkImages
{
	class Image ;
}

namespace nkWinUi
{
	enum class LAYOUT_TYPE ;

	class Font ;
	class InputDescriptor ;
	class Layout ;
	class ScrollBar ;
	class System ;
	class Theme ;

	struct ChangeEventData ;
	struct CallbackStorage ;
	struct ClickEventData ;
	struct KeyEventData ;
	struct WheelEventData ;
}

/// Includes ---------------------------------

// nkWinUi
#include "../Dll/DllDefines.h"

#include "../Enums/BorderKind.h"

#include "../Inputs/HandledEventData.h"

#include "../Inputs/InputCodes.h"

#include "ComponentType.h"

// nkExport
#include <NilkinsExport/Exportable/Exportable.h>

// nkMaths
#include <NilkinsMaths/Geometry/Point.h>
#include <NilkinsMaths/Geometry/Rectangle.h>

// nkMemory
#include <NilkinsMemory/Containers/BufferCast.h>
#include <NilkinsMemory/Containers/StringView.h>
#include <NilkinsMemory/Containers/String.h>

// Standards
#include <functional>

/// Class ------------------------------------

namespace nkWinUi
{
	class DLL_WINUI_EXPORT Component : public nkExport::Exportable
	{		
		public :
		
			// Constructor, destructor
			Component (System* system) noexcept ;
			virtual ~Component () ;

			// Getters
			Layout* getLayout () const ;
			Theme* getTheme () const ;
			Font* getFont () const ;
			nkMaths::Point getPositionInParent () const ;
			nkMaths::Point getPositionInScreen () const ;
			float getWidth () const ;
			float getHeight () const ;
			nkMaths::Rectangle getAreaInParent () const ;
			nkMaths::Rectangle getAreaInScreen () const ;
			virtual nkMaths::Point getBorderExtents () const ;
			virtual float getBorderExtent (BORDER_KIND border) const ;
			virtual float getLayoutAllowedWidth () const ;
			virtual float getLayoutAllowedHeight () const ;
			virtual float getLayoutAllowedOffsetX () const ;
			virtual float getLayoutAllowedOffsetY () const ;
			bool isInitialized () const ;
			System* getSystem () const ;
			Component* getParentComponent () const ;
			COMPONENT_TYPE getComponentType () const ;
			nkMemory::StringView getComponentName () const ;
			bool getVisibility () const ;
			virtual nkMemory::StringView getLabel () const ;
			void* getData () const ;
			bool isEnabled () const ;
			bool isForegroundWindow () const ;
			virtual unsigned int getZDepth () const ;
			bool getVisibleOnLoad () const ;
			std::function<bool (Component*)> getCloseCallback () const ;
			std::function<void (Component*, bool)> getVisibilityCallback () const ;
			std::function<void (Component*, const ClickEventData&)> getClickCallback () const ;
			std::function<void (Component*, const WheelEventData&)> getWheelCallback () const ;
			std::function<void (Component*, const KeyEventData&)> getKeyCallback () const ;

			// Setters
			virtual Layout* setLayout (LAYOUT_TYPE layoutType) ;
			virtual void setTheme (Theme* theme) ;
			virtual void setFont (Font* font) ;
			virtual void setPositionInParent (nkMaths::Point position) ;
			virtual void setPositionInScreen (nkMaths::Point position) ;
			virtual void setSize (float width, float height) ;
			virtual void setWidth (float width) ;
			virtual void setHeight (float height) ;
			void setMinSize (float width, float height) ;
			void setMaxSize (float width, float height) ;
			void setRatio (float widthOverHeight) ;
			virtual void setAreaInParent (const nkMaths::Rectangle& area) ;
			virtual void setAreaInScreen (const nkMaths::Rectangle& area) ;
			virtual void setParentComponent (Component* parent, bool makeItVisible = true) ;
			virtual void setLabel (nkMemory::StringView label) ;
			void setComponentName (nkMemory::StringView name) ;
			virtual void setVisibility (bool value) ;
			void setData (void* data) ;
			void setEnabled (bool value) ;
			void setVisibleOnLoad (bool value) ;
			void setCloseCallback (std::function<bool (Component* caller)> callback) ;
			void setVisibilityCallback (std::function<void (Component* caller, bool visibility)> callback) ;
			void setClickCallback (std::function<void (Component* caller, const ClickEventData& eventData)> callback) ;
			void setWheelCallback (std::function<void (Component* caller, const WheelEventData& eventData)> callback) ;
			void setKeyCallback (std::function<void (Component* caller, const KeyEventData& eventData)> callback) ;
				
			// Hierarchy
			void addChild (Component* child, bool makeItVisible = true) ;
			void removeChild (Component* child) ;
			void removeChild (unsigned int index) ;
			Component* getChild (unsigned int index) ;
			unsigned int getChildIndex (Component* child) ;
			void unloadWithChildren () ;
			void loadWithChildren () ;
			void updateZDepth () ;

			// Utils
			void bringToForeground () ;
			void focusWindow () ;

			// Conversions
			nkMaths::Point getCoordRelativeFromAbsolute (nkMaths::Point absCoords) ;
			nkMaths::Point getCoordAbsoluteFromRelative (nkMaths::Point relCoords) ;

			// Init
			virtual void load () = 0 ;
			virtual void unload () = 0 ;
			void reload () ;

			// Update
			virtual void updateWindow () ;

			// Images
			nkImages::Image paintToImage (bool withFrame = false) ;

			// Events
			void simulateEvent (const InputDescriptor& inputDescription) ;
			virtual void onSized () ;

			// Export / Import
			virtual void exportClassToTree (nkExport::Node* rootNode) override ;
			virtual void exportIntrospection (nkExport::Node* rootNode) ;
			virtual void importClassFromTree (nkExport::Node* rootNode) override ;

		protected :

			// Functions
			// Export utils
			virtual void _retrieveChildren (std::vector<Component*>& container) ;

			// Unload utils
			bool _unloadCloseRequest () ;

		protected :
		
			// Attributes
			// Layout & theme
			Layout* _layout ;
			Theme* _theme ;
			Font* _font ;

			// Events
			CallbackStorage* _callbacks ;

			// Size
			std::pair<float, float> _minSize ;
			std::pair<float, float> _maxSize ;
			nkMaths::Rectangle _area ;

			// Potential view ratio
			float _ratio ;

			// Type for reflection
			COMPONENT_TYPE _componentType ;

			// Parents
			System* _system ;
			Component* _parentComponent ;
			// Children list
			nkMemory::BufferCast<Component*> _children ;

			// Name and label
			nkMemory::String _componentName ;
			nkMemory::String _label ;

			// User data
			void* _data ;

			// Depth in ui
			unsigned int _zDepth ;

			// Flags
			bool _initialized ;
			bool _enabled ;
			bool _visibleOnLoad ;
	} ;
}